package wscmd

import (
	"encoding/json"
	"go.uber.org/zap"
	"wzgames/internal/admin/adc"
	"wzgames/internal/admin/adcomm"
	"wzgames/internal/admin/api/wzabind"
	"wzgames/internal/codec/sfs"
	"wzgames/internal/constant"
	"wzgames/internal/gvalidator"
	"wzgames/internal/model/mcomm"
	"wzgames/internal/response"
	"wzgames/internal/secure"
	"wzgames/pkg/logger"
	"wzgames/pkg/utils/byteutil"
)

func registerAdminCmds() {
	cmdSv.RegisterCmd(adcomm.CmdAdminKick, adminKick)
	cmdSv.RegisterCmd(adcomm.CmdAdminAdd, adminAdd)
	cmdSv.RegisterCmd(adcomm.CmdAdminPwd, adminPwd)
	cmdSv.RegisterCmd(adcomm.CmdAdminStatus, adminStatus)
}

func adminKick(admin adcomm.IAdmin, ipt interface{}) {
	m := ipt.(*sfs.TSfsObject)
	data := m.GetContent()
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminKick, "bad params")
		return
	}
	data = data.GetSFSObject(sfs.ParamId)
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminKick, "bad params")
		return
	}
	adminName := data.GetUtfString("data")
	if !gvalidator.IsAlphaNumeric(adminName) {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminKick, "bad params")
		return
	}
	admObj, code := adc.PP().GetAdminByName(adminName)
	if code != 0 {
		admin.ErrMsg(code, adcomm.CmdAdminKick, "")
		return
	}
	adm := adc.GetReceiver().GetAdmin(admObj.AdminID)
	if adm != nil {
		adm.Logout()
	}

	msg := response.AcquireMsgO13()
	xw := sfs.XWriter{}
	defer xw.Reset()
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, adcomm.CmdAdminKick)
	xw.WriteSfsObjectPre(sfs.ParamId, uint16(2))
	xw.WriteShortS(sfs.KeyCode, code)
	xw.WriteStringS(constant.KeyUsername, adminName)

	xw.WriteTo(msg)
	admin.SendMessage(msg)
}

func adminAdd(admin adcomm.IAdmin, ipt interface{}) {
	m := ipt.(*sfs.TSfsObject)
	data := m.GetContent()
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminAdd, "bad params")
		return
	}
	data = data.GetSFSObject(sfs.ParamId)
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminAdd, "bad params")
		return
	}
	dataJson := data.GetUtfString("data")
	req := wzabind.SysAddAdminReq{}
	err := json.Unmarshal(byteutil.StringToSliceByte(dataJson), &req)
	if err != nil {
		logger.Error("[WsCmd] add admin fail on json.Unmarshal", zap.String("Input", dataJson), zap.Error(err))
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminAdd, "bad params")
		return
	}
	if !gvalidator.IsAlphaNumeric(req.AdminName) || !gvalidator.IsAlphaNumeric(req.AdminPassword) {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminAdd, "bad params - 1")
		return
	}
	req.AdminPassword = secure.Md5Hex(byteutil.StringToSliceByte(req.AdminPassword))
	_, code := adc.PP().GetAdminByName(req.AdminName)
	if code == 0 {
		admin.ErrMsg(response.ErrDuplicate, adcomm.CmdAdminAdd, "admin exists")
		return
	} else if code != response.ErrNotFound {
		admin.ErrMsg(code, adcomm.CmdAdminAdd, "")
		return
	}
	if req.NickName == "" {
		req.NickName = req.AdminName
	}
	_, code = adc.PP().CreateAdmin(req)
	if code != 0 {
		admin.ErrMsg(code, adcomm.CmdAdminAdd, "create fail")
		return
	}

	msg := response.AcquireMsgO13()
	xw := sfs.XWriter{}
	defer xw.Reset()
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, adcomm.CmdAdminAdd)
	xw.WriteSfsObjectPre(sfs.ParamId, uint16(2))
	xw.WriteShortS(sfs.KeyCode, code)
	xw.WriteStringS(constant.KeyUsername, req.AdminName)

	xw.WriteTo(msg)
	admin.SendMessage(msg)
}

func adminPwd(admin adcomm.IAdmin, ipt interface{}) {
	m := ipt.(*sfs.TSfsObject)
	data := m.GetContent()
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminPwd, "bad params")
		return
	}
	data = data.GetSFSObject(sfs.ParamId)
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminPwd, "bad params")
		return
	}
	dataJson := data.GetUtfString("data")
	req := wzabind.SysAddAdminReq{}
	err := json.Unmarshal(byteutil.StringToSliceByte(dataJson), &req)
	if err != nil {
		logger.Error("[WsCmd] modify admin pwd fail on json.Unmarshal", zap.String("Input", dataJson), zap.Error(err))
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminPwd, "bad params")
		return
	}
	if !gvalidator.IsAlphaNumeric(req.AdminName) || !gvalidator.IsAlphaNumeric(req.AdminPassword) {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminPwd, "bad params - 1")
		return
	}
	admObj, code := adc.PP().GetAdminByName(req.AdminName)
	if code != 0 {
		admin.ErrMsg(code, adcomm.CmdAdminPwd, "")
		return
	}
	code = adc.PP().ChangeAdminPwd(admObj, secure.Md5Hex(byteutil.StringToSliceByte(req.AdminPassword)))
	if code != 0 {
		admin.ErrMsg(code, adcomm.CmdAdminPwd, "change pwd fail")
		return
	}

	adm := adc.GetReceiver().GetAdmin(admObj.AdminID)
	if adm != nil {
		adm.Logout()
	}

	msg := response.AcquireMsgO13()
	xw := sfs.XWriter{}
	defer xw.Reset()
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, adcomm.CmdAdminPwd)
	xw.WriteSfsObjectPre(sfs.ParamId, uint16(2))
	xw.WriteShortS(sfs.KeyCode, code)
	xw.WriteStringS(constant.KeyUsername, req.AdminName)

	xw.WriteTo(msg)
	admin.SendMessage(msg)
}

func adminStatus(admin adcomm.IAdmin, ipt interface{}) {
	m := ipt.(*sfs.TSfsObject)
	data := m.GetContent()
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminStatus, "bad params")
		return
	}
	data = data.GetSFSObject(sfs.ParamId)
	if data == nil {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminStatus, "bad params")
		return
	}
	dataJson := data.GetUtfString("data")
	req := wzabind.SysAddAdminReq{}
	err := json.Unmarshal(byteutil.StringToSliceByte(dataJson), &req)
	if err != nil {
		logger.Error("[WsCmd] modify admin status fail on json.Unmarshal", zap.String("Input", dataJson), zap.Error(err))
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminStatus, "bad params")
		return
	}
	if !gvalidator.IsAlphaNumeric(req.AdminName) || (req.Status != mcomm.Status_Up && req.Status != mcomm.Status_Down && req.Status != mcomm.Status_Suspended) {
		admin.ErrMsg(response.ErrBadRequest, adcomm.CmdAdminStatus, "bad params - 1")
		return
	}
	admObj, code := adc.PP().GetAdminByName(req.AdminName)
	if code != 0 {
		admin.ErrMsg(code, adcomm.CmdAdminStatus, "")
		return
	}
	code = adc.PP().ChangeAdminStatus(admObj, req.Status)
	if code != 0 {
		admin.ErrMsg(code, adcomm.CmdAdminStatus, "change admin status fail")
		return
	}

	adm := adc.GetReceiver().GetAdmin(admObj.AdminID)
	if adm != nil {
		adm.Logout()
	}

	msg := response.AcquireMsgO13()
	xw := sfs.XWriter{}
	defer xw.Reset()
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, adcomm.CmdAdminStatus)
	xw.WriteSfsObjectPre(sfs.ParamId, uint16(3))
	xw.WriteShortS(sfs.KeyCode, code)
	xw.WriteStringS(constant.KeyUsername, req.AdminName)
	xw.WriteIntS(constant.KeyState, int32(req.Status))

	xw.WriteTo(msg)
	admin.SendMessage(msg)
}
